package cscie160.hw6;

import java.io.PrintStream;
import java.util.StringTokenizer;
/**
 * This class is responsible for executing client requests.
 * @author Michael Melnikov
*/
public class ATMRunnable implements Runnable
{
    private String commandLine;
    private String transactionRequest;
    private Float amount;
    private ATM atm;
    private PrintStream out;
    private StringBuffer result;

    /**
     * no-args constructor creates object setting transactionRequest to null
    */
    public ATMRunnable()
    {
        this.commandLine = null;
        transactionRequest = null;
        result = null;
        //atm = new ATMImplementation();
    }


    /**
     * sets the commandLine
    */
    protected void setCommandLine(String commandLine)
    {
        this.commandLine = commandLine;
    }

    /**
     * sets the output print stream
    */
    protected void setPrintStream(PrintStream printStream)
    {
        out = printStream;
    }

    protected void setAtm(ATM atm)
    {
        this.atm = atm;
    }

    /**
     * manages all the functionality of the class
    */
    public void run()
    {
        try
        {
            if (parseRequest(commandLine))
                invokeAtmMethod();
        }
        catch (ATMException atmex)
        {
            System.out.println(getClass().getName() + " method=run." + atmex.getMessage());
        }
        System.out.println(getClass().getName() + " method=run. Result will be reported");
        reportResult();
        System.out.println(getClass().getName() + " method=run. Result reported");
    }

    /**
     * parses the request string.
     * Upon parsing, determines the operation to perform and amount to apply
     * @return boolean
    */
    private boolean parseRequest(String commandLine) throws ATMException
    {
        // Break out the command line into String[]
        if (commandLine == null)
            return false;
        System.out.println(getClass().getName() + " method=parseRequest. commandLine="+commandLine);
        StringTokenizer tokenizer = new StringTokenizer(commandLine);

        String commandAndParam[] = new String[tokenizer.countTokens()];

        int index = 0;

        while (tokenizer.hasMoreTokens())
        {

            commandAndParam[index++] = tokenizer.nextToken();

        }

        String command = commandAndParam[0];

        this.transactionRequest = command;

        // Dispatch BALANCE request without further information.

        if (command.equalsIgnoreCase(Commands.BALANCE.toString()))
        {


            return true;
        } 
        if (!command.equalsIgnoreCase(Commands.DEPOSIT.toString())
            && !command.equalsIgnoreCase(Commands.WITHDRAW.toString()))
        {

            throw new ATMException("Unrecognized command: " + command);

        }
  

        // Must have 2nd arg for amount when processing DEPOSIT/WITHDRAW commands

        if (commandAndParam.length < 2)
        {

            throw new ATMException("Missing amount for command \"" + command + "\"");

        }

        try
        {

            float amount = Float.parseFloat(commandAndParam[1]);

            this.amount = amount;
        }
        catch (NumberFormatException nfe)
        {
            throw new ATMException("Unable to make float from input: " + commandAndParam[1]);

        }

        return true;
    }

    /**
     * invokes appropriate atm operation
    */
    private void invokeAtmMethod() throws ATMException
    {
        //if (result == null)
            result = new StringBuffer();
        //result.append(transactionRequest);
        //result.append("=");

        if (transactionRequest.equalsIgnoreCase(Commands.BALANCE.toString()))
        {

            Float balance = atm.getBalance();

            result.append(balance.toString());
        }
        else if (transactionRequest.equalsIgnoreCase(Commands.DEPOSIT.toString()))
        {

            atm.deposit(amount);

            //result.append(amount.toString());
        }
        else if (transactionRequest.equalsIgnoreCase(Commands.WITHDRAW.toString()))
        {

            atm.withdraw(amount);
            //result.append(amount.toString());           
        }
        System.out.println(getClass().getName() + " method=invokeAtmMethod. result=\""+result+"\"");         
    }

    /**
     * sends a message back to the client, reporting the operation result
    */
    private void reportResult()
    {
        if (result != null && result.length() != 0)
        out.println(result.toString());

        //out.notifyAll();
    }
}
